﻿ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms.DataVisualization.Charting;
using System.Drawing;

namespace WebBrowserTest
{
    public class ChartBuilder
    {
        #region private members
        private List<DateTime> _xAxisVal;
        private List<int> _yAxisVal;
        private Chart _chart;
        private int _width = 1300;
        private int _height=400;
        private bool inverted = false;
        private bool isMultiSeries = true;
        private Dictionary<string, Dictionary<DateTime, int>> points = new Dictionary<string, Dictionary<DateTime, int>>();
        private string _serieName;
        private int maxYValue;
        private int minYValue = int.MaxValue;
        /*marker variables*/
        private Color _defaultMarkerColor = Color.Blue;
        private Color _selectedMarkerColor = Color.Red;
        private int _markerDefaultSize = 9;
        private int _markerBigSize = 11;
        private Dictionary<string, DataPoint> _prevSelectedPoint = new Dictionary<string, DataPoint>();
        private Dictionary<string, Color> _defaultMarkerColors = new Dictionary<string, Color>();

        
        #endregion
        #region .ctor
        public ChartBuilder(Chart chart,List<DateTime> xAxisValues, List<int> yAxisValues)
        {
            _xAxisVal = xAxisValues;
            _yAxisVal = yAxisValues;
            _chart = chart;
            minYValue = int.MaxValue;
            maxYValue = 0;

            
        } 
        #endregion

        public bool IsInverted
        {
            get{ return inverted;}
            set
            {
                this.inverted = value;
                foreach (var area in _chart.ChartAreas)
                {
                    area.AxisY.IsReversed = value;
                }
            }
        }
        public int XAxisMin{ get; set;}
        public int Interval{ get; set;}
        public bool MultiSeries
        {
            get { return isMultiSeries; }
            set { isMultiSeries = value; }
        }

        public ChartValueType XAxisType { get; set; }

        public int Width
        {
            get { return _width; }
            set 
            { 
                _width = value;
                _chart.Width = value;
            }
        }

        public int Height
        {
            get { return _height; }
            set
            {
                _height = value;
                _chart.Height = value;
            }
        }

        public Series AddSerie(string serieName, List<DateTime> xAxisValues, List<int> yAxisValues, bool inverted)
        {
            _serieName = serieName;
            _yAxisVal = yAxisValues;
            _xAxisVal = xAxisValues;
            points[_serieName] = new Dictionary<DateTime, int>();
            for (int i = 0; i < _xAxisVal.Count; i++)
            {
                if (!points[serieName].ContainsKey(xAxisValues[i]))
                {
                    points[_serieName].Add(xAxisValues[i], i);
                }
            }

            this.inverted = inverted;
            var seriesToDel = new List<Series>();
            if (_chart.Series.Where(o=>o.Name == serieName).FirstOrDefault() != null)
            {
                var s = _chart.Series.Where(o => o.Name == serieName).FirstOrDefault();
                _chart.Series.Remove(s);
            }
            
            if(!MultiSeries)
            {
                seriesToDel.AddRange(_chart.Series);
                foreach (var serie in seriesToDel)
                {
                    _chart.Series.Remove(serie);
                }
            }
            Series series = GetSeries(serieName, xAxisValues, yAxisValues);
            _chart.Series.Add(series);

            ChartArea area = GetArea();
            if (_chart.ChartAreas.Count > 0)
            {
                _chart.ChartAreas.RemoveAt(0);
            }
            _chart.ChartAreas.Add(area);
            _chart.Width = Width;
            _chart.Height = Height;
            return series;
        }



        public void HighlightPoint(DateTime value)
        {
           
            foreach (var dataPoint in _prevSelectedPoint)
            {
                dataPoint.Value.MarkerColor = _defaultMarkerColors[dataPoint.Key];
                dataPoint.Value.MarkerSize = _markerDefaultSize;
                dataPoint.Value.IsValueShownAsLabel = false;
            }
            _prevSelectedPoint.Clear();
            foreach (var serie in _chart.Series)
            {
                var point = serie.Points[points[serie.Name][value.Date]];
                if (point != null)
                {
                    point.MarkerColor = Color.Red;
                    point.MarkerSize = _markerBigSize;
                    point.IsValueShownAsLabel = true;
                    _prevSelectedPoint.Add(serie.Name,point);
                }
            }
         
            
        }

        private ChartArea GetArea()
        {
            ChartArea chartArea1 = new ChartArea();
            chartArea1.Area3DStyle.Inclination = 40;
            chartArea1.Area3DStyle.IsClustered = true;
            chartArea1.Area3DStyle.IsRightAngleAxes = false;
            chartArea1.Area3DStyle.LightStyle = System.Windows.Forms.DataVisualization.Charting.LightStyle.Realistic;
            chartArea1.Area3DStyle.Perspective = 9;
            chartArea1.Area3DStyle.Rotation = 25;
            chartArea1.Area3DStyle.WallWidth = 3;
            chartArea1.AxisX.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
            chartArea1.AxisX.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.AxisX.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.AxisY.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
            chartArea1.AxisY.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.AxisY.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.BackColor = System.Drawing.Color.OldLace;
            chartArea1.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom;
            chartArea1.BackSecondaryColor = System.Drawing.Color.White;
            chartArea1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
            chartArea1.BorderDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;
            chartArea1.Name = "Default";
            chartArea1.ShadowColor = System.Drawing.Color.Transparent;
            /*compute min/max values*/
            chartArea1.AxisX.LabelStyle.Format = "yyyy-MM-dd";

            //var sub = chartArea1.AxisY.Maximum - chartArea1.AxisY.Minimum;
            int maxVal = _yAxisVal.OrderByDescending(o => o).First() + 2;
            if(maxVal > maxYValue)
            {
                maxYValue = maxVal;
            }
            int minValue = _yAxisVal.OrderBy(o => o).First() - 2;
            if(minValue < minYValue)
            {
                minYValue = minValue;
            }
            var sub = maxYValue - minYValue;
            chartArea1.AxisY.Maximum = maxYValue;
            chartArea1.AxisY.Minimum = IsInverted ? 1 : minYValue;
            chartArea1.AxisY.IsReversed = IsInverted;

            /*compute interval*/
            int interval = 1;
          
            if(sub > 20 && sub < 1000)
            {
                interval = (int)sub/10;
            }
            
            if (sub > 50)
            {
                chartArea1.AxisY.IsLogarithmic = true;
                chartArea1.AxisY.LogarithmBase = 10.0d;
                chartArea1.AxisY.Maximum = 10*maxYValue;
            }
            chartArea1.AxisY.Interval = interval;
            return chartArea1;
        }
        private Series GetSeries(string serieName, List<DateTime> xAxisValues, List<int> yAxisValues)
        {
            Series s = new Series();
            s.Name = serieName;
            s.ChartType = SeriesChartType.Line;
            s.XValueType = XAxisType;
            s.YValueType = ChartValueType.Int32;
            s.MarkerSize = 9;
            s.MarkerStyle = MarkerStyle.Circle;
            if (!_defaultMarkerColors.ContainsKey(serieName))
            {
                _defaultMarkerColors.Add(serieName, s.MarkerColor);
            }
            s.IsValueShownAsLabel = showValuesAsLabel;
            for (int i = 0; i < xAxisValues.Count; i++)
            {
                s.Points.AddXY(xAxisValues[i], yAxisValues[i]);
            }
            return s;
        }

        private bool showValuesAsLabel = true;
        public bool ShowPointsValues
        {
            set
            {
                foreach (var series in _chart.Series)
                {
                    series.IsValueShownAsLabel = value;

                }
                showValuesAsLabel = value;
            }
        }
    }

}
